package com.common.app.widget.floatingView

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ActivityInfo
import android.graphics.PixelFormat
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
import android.widget.ImageView
import androidx.appcompat.widget.LinearLayoutCompat
import com.common.app.R
import com.common.base.utils.ViewUtils.dp2px
//import pl.droidsonroids.gif.GifImageView
import kotlin.math.abs


/**
 *
 * 作者：sosou
 *
 * 版本：1.0
 *
 * 创建日期：16/2/2023
 *
 * 描述：拖动view，用于悬浮窗，无需上层应用权限
 *
 * 修订历史：
 *
 */
@SuppressLint("ViewConstructor")
class SFloatingView(private val mContext: Context, private val onClickAction: () -> Unit) :
    LinearLayoutCompat(
        mContext
    ) {
    private var mFloatBallParamsX = 0 //view 位置初始x
    private var mFloatBallParamsY = 300 // view  位置初始y
    private var inputStartX = 0
    private var inputStartY = 0
    private var viewStartX = 0
    private var viewStartY = 0
    private var mFloatBallParams: WindowManager.LayoutParams? = null
    private var mWindowManager: WindowManager? = null
    private var mValueAnimator: ValueAnimator? = null
    private var mScreenHeight = 0
    private var mScreenWidth = 0
    private var mBotParamsYScale = 8
    private var isShow = false
    private var moveVertical = false
    private var isDrag = false
    private var slop = 0

//    private var mImg: GifImageView? = null
    private var mImg: ImageView? = null

    private var mDpWidth = 0

    // 新增：“仅沿屏幕右侧上下拖拽”的开关（默认关闭）
    private var rightEdgeVerticalDragOnly: Boolean = false
    // 与原 welt() 逻辑一致的底部偏移量
    private val bottomOffsetPx: Int = dp2px(60)

    private fun init() {
        initFloatViewParams(mContext)
        mScreenWidth = mContext.resources.displayMetrics.widthPixels
        mScreenHeight = mContext.resources.displayMetrics.heightPixels
        mDpWidth = dp2px(30f).toInt()
        slop = 3

        mImg = findViewById(R.id.floating_view_img)

        initLocation()
    }

    /**
     * 对外开关：设置是否仅沿屏幕右侧上下拖拽
     */
    fun setRightEdgeVerticalDragOnly(enabled: Boolean) {
        rightEdgeVerticalDragOnly = enabled
        mFloatBallParams?.let {
            if (enabled) {
                val edgeX = mScreenWidth - (if (width > 0) width else mDpWidth)
                it.x = edgeX
                val h = if (height > 0) height else mDpWidth
                val maxY = mScreenHeight - (h + bottomOffsetPx)
                it.y = if (maxY > 0) it.y.coerceIn(0, maxY) else 0
            }
            // 仅当已附着到 WindowManager 时才更新布局；否则缓存位置，等 showWindow 后再生效
            if (this.parent != null) {
                updateWindowManager()
            } else {
                mFloatBallParamsX = it.x
                mFloatBallParamsY = it.y
            }
        }
    }

    /**
     * 显示悬浮
     */
    fun initLocation() {
        if (mFloatBallParamsX == -1 || mFloatBallParamsY == -1) {
            //首次打开时，初始化的位置
            mFloatBallParams?.x = mScreenWidth - mDpWidth
            mFloatBallParams?.y = mScreenHeight - mDpWidth * 2
            mFloatBallParamsX = mFloatBallParams?.x ?: 0
            mFloatBallParamsY = mFloatBallParams?.y ?: 0
        } else {
            //首次打开时，初始化的位置
            mFloatBallParams?.x = mScreenWidth - mDpWidth
            mFloatBallParams?.y = mScreenHeight - mDpWidth * mBotParamsYScale
        }
        // 开关开启时，确保吸附在右侧
        if (rightEdgeVerticalDragOnly) {
            mFloatBallParams?.x = mScreenWidth - (if (width > 0) width else mDpWidth)
        }
    }

    /**
     * 显示悬浮
     */
    fun showFloat() {
        isShow = true
        if (mFloatBallParamsX == -1 || mFloatBallParamsY == -1) {
            //首次打开时，初始化的位置
            mFloatBallParams?.x = mScreenWidth - mDpWidth
            mFloatBallParams?.y = mScreenHeight - mDpWidth * 2
            mFloatBallParamsX = mFloatBallParams?.x ?: 0
            mFloatBallParamsY = mFloatBallParams?.y ?: 0
        } else {
//            mFloatBallParams?.x = mFloatBallParamsX
//            mFloatBallParams?.y = mFloatBallParamsY

            //首次打开时，初始化的位置
            mFloatBallParams?.x = mScreenWidth - mDpWidth
            mFloatBallParams?.y = mScreenHeight - mDpWidth * mBotParamsYScale
        }
//        if(this.windowToken == null){
//            mWindowManager?.addView(this, mFloatBallParams)
//        }
        showWindow()
        if (rightEdgeVerticalDragOnly) {
            // 固定到右侧，不执行吸附动画
            mFloatBallParams?.x = mScreenWidth - (if (width > 0) width else mDpWidth)
            updateWindowManager()
        } else {
            //吸附贴边计算和动画
            welt()
        }
    }

    /**
     * 关闭
     */
    fun dismissFloatView() {
        isShow = false
        try {
            hideWindow()
            mWindowManager?.removeViewImmediate(this)
        } catch (e: IllegalArgumentException) {
            Log.e("SFloatingView", "view not found")
        }
    }

    /**
     * 显示小窗口
     */
    fun showWindow() {
//        Log.i(TAG, "showWindow")
        if (this.parent == null) {
            mWindowManager?.addView(this, mFloatBallParams)
        } else {
            mWindowManager?.updateViewLayout(this, mFloatBallParams)
        }
    }

    /**
     * 隐藏小窗口
     */
    fun hideWindow() {
//        Log.i(TAG, "hideWindow")
        if (this.parent != null) {
            mWindowManager?.removeView(this)
        }
    }


    //拖动操作
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                //Log.e("----", "按下" + mFloatBallParamsX + "-----" + mFloatBallParamsY);
                if (null != mValueAnimator && mValueAnimator?.isRunning == true) {
                    mValueAnimator?.cancel()
                }
                isPressed = true
                isDrag = false
                inputStartX = event.rawX.toInt()
                inputStartY = event.rawY.toInt()
                viewStartX = mFloatBallParams?.x ?: 0
                viewStartY = mFloatBallParams?.y ?: 0
            }
            MotionEvent.ACTION_MOVE -> {
                val inMovingX = event.rawX.toInt()
                val inMovingY = event.rawY.toInt()
                val moveX = viewStartX + inMovingX - inputStartX
                val moveY = viewStartY + inMovingY - inputStartY
                if (mScreenHeight <= 0 || mScreenWidth <= 0) {
                    isDrag = false
                }

                if (rightEdgeVerticalDragOnly) {
                    // 仅沿右侧垂直拖拽
                    isDrag = abs(inMovingY - inputStartY) > slop
                    val edgeX = mScreenWidth - (if (width > 0) width else mDpWidth)
                    mFloatBallParams?.x = edgeX

                    var newY = moveY
                    val h = if (height > 0) height else mDpWidth
                    val maxY = mScreenHeight - (h + bottomOffsetPx)
                    newY = if (maxY > 0) newY.coerceIn(0, maxY) else 0

                    mFloatBallParams?.y = newY
                    updateWindowManager()
                } else {
                    if (abs(inMovingX - inputStartX) > slop && abs(inMovingY - inputStartY) > slop) {
                        isDrag = true
                        mFloatBallParams?.x = moveX
                        mFloatBallParams?.y = moveY
                        updateWindowManager()
                    } else {
                        isDrag = false
                    }
                }
            }
            MotionEvent.ACTION_UP -> {
                //Log.e("----", "抬起" + mFloatBallParamsX + "-----" + mFloatBallParamsY);
                if (isDrag) {
                    //恢复按压效果
                    isPressed = false
                } else {
                    //点击操作
                    if (isFastClick) {
                        onClickAction.invoke()
                    }
                }

                if (rightEdgeVerticalDragOnly) {
                    // 固定到右侧，Y 做边界限制
                    val edgeX = mScreenWidth - (if (width > 0) width else mDpWidth)
                    mFloatBallParams?.x = edgeX
                    mFloatBallParams?.y = (mFloatBallParams?.y ?: 0).let { curY ->
                        val h = if (height > 0) height else mDpWidth
                        val maxY = mScreenHeight - (h + bottomOffsetPx)
                        if (maxY > 0) curY.coerceIn(0, maxY) else 0
                    }
                    updateWindowManager()
                } else {
                    //吸附贴边计算和动画
                    welt()
                }
            }
            else -> {}
        }
        return isDrag || super.onTouchEvent(event)
    }

    /**
     * 贴边逻辑
     */
    private fun welt() {
        mFloatBallParams?.let {

            var movedX = it.x
            var movedY = it.y
            moveVertical = false
            if (it.y < height && it.x >= slop && it.x <= mScreenWidth - width - slop) {
                movedY = 0
            } else if (it.y > mScreenHeight - height * 2 && it.x >= slop && it.x <= mScreenWidth - width - slop) {
                movedY = mScreenHeight - (height+bottomOffsetPx)//加底部偏移量防止控件覆盖到页面底部tab栏
            } else {
                moveVertical = true
                movedX =
                    if (it.x < mScreenWidth / 2 - width / 2) 0 else mScreenWidth - width
            }
            val duration: Int
            if (moveVertical) {
                mValueAnimator = ValueAnimator.ofInt(it.x, movedX)

                duration = movedX - it.x
            } else {
                mValueAnimator = ValueAnimator.ofInt(it.y, movedY)
                duration = movedY - it.y
//                duration = movedY - it.y - mDpWidth * 2
            }
            mValueAnimator?.duration = abs(duration).toLong()
            mValueAnimator?.addUpdateListener { animation: ValueAnimator ->
                val level = animation.animatedValue as Int
                if (moveVertical) {
                    it.x = level

//                    if (movedX >= 0 && movedY >= (mScreenHeight - (this.width * 3))) {
////                        it.y = mScreenHeight - mDpWidth * 10
//                        it.y = movedY -(this.width * 1.5).toInt()
//                    }
                } else {
//                    it.y = level
                    it.y = level - mDpWidth * 2
                }
                updateWindowManager()
            }
            mValueAnimator?.interpolator = AccelerateInterpolator()
            mValueAnimator?.start()
        }
    }


    /**
     * 更新保存位置
     */
    private fun updateWindowManager() {
        mFloatBallParams?.let { params ->
            // 未附着到 WindowManager 时，直接返回（同时缓存坐标），避免 IllegalArgumentException
            if (this.parent == null) {
                mFloatBallParamsX = params.x
                mFloatBallParamsY = params.y
                return
            }
            mWindowManager?.updateViewLayout(this, params)
            mFloatBallParamsX = params.x
            mFloatBallParamsY = params.y
        }
    }

    override fun onDetachedFromWindow() {
        //进入下个页面的时候贴边动画暂停，
        // 下个页面attached时候会继续动画，
        // 你手速快的话还能在中途接住球继续拖动
        mValueAnimator?.cancel()
        super.onDetachedFromWindow()
    }

    /**
     * 横竖切屏后调用，否则贴边计算异常
     *
     * @param orientation
     */
    fun setScreenOrientation(orientation: Int) {
        if (orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
            || orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        ) {
            mScreenWidth = mContext.resources.displayMetrics.widthPixels
            mScreenHeight = mContext.resources.displayMetrics.heightPixels
        } else {
            mScreenWidth = mContext.resources.displayMetrics.heightPixels
            mScreenHeight = mContext.resources.displayMetrics.widthPixels
        }

        // 开关开启时，切换方向后也保持靠右并限制 Y
        if (rightEdgeVerticalDragOnly) {
            mFloatBallParams?.let {
                val edgeX = mScreenWidth - (if (width > 0) width else mDpWidth)
                it.x = edgeX
                val h = if (height > 0) height else mDpWidth
                val maxY = mScreenHeight - (h + bottomOffsetPx)
                if (maxY > 0) {
                    it.y = it.y.coerceIn(0, maxY)
                } else {
                    it.y = 0
                }
                updateWindowManager()
            }
        }
    }


    /**
     * 获取view参数
     *
     * @param mContext
     */
    private fun initFloatViewParams(mContext: Context) {
        mFloatBallParams = WindowManager.LayoutParams()
        mFloatBallParams?.let {
            it.flags =
                (it.flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //避免悬浮球被通知栏部分遮挡
                        or WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
            it.dimAmount = 0.2f

            it.height = WindowManager.LayoutParams.WRAP_CONTENT
            it.width = WindowManager.LayoutParams.WRAP_CONTENT
            it.gravity = Gravity.START or Gravity.TOP
            it.format = PixelFormat.RGBA_8888
            // 设置整个窗口的透明度
            it.alpha = 1.0f
            // 显示悬浮球在屏幕左上角
            it.x = 0
            it.y = 0
            mWindowManager = mContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        }
    }

    companion object {
        private const val TAG = "FloatingView"
        private const val MIN_CLICK_DELAY_TIME = 500L
        var lastClickTime = 0L
        val isFastClick: Boolean
            get() {
                var flag = false
                val curClickTime = System.currentTimeMillis()
                if (curClickTime - lastClickTime >= MIN_CLICK_DELAY_TIME) {
                    flag = true
                }
                lastClickTime = curClickTime
                return flag
            }
    }

    init {
        val inflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        inflater.inflate(R.layout.layout_floating_view, this)
        init()
    }

    fun getImgView(): ImageView? {
        return mImg
    }
}